{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c04328e8-ef2d-4900-bc94-67768490a174",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.cluster import KMeans\n",
    "from sklearn.metrics import pairwise_distances_argmin_min\n",
    " \n",
    "# 一、k-Means聚类算法实现与验证\n",
    "def kmeans(X, k, max_iters=100):\n",
    "    # 初始化k个中心点（随机选择）\n",
    "    centroids = X[np.random.choice(X.shape[0], k, replace=False)]\n",
    "    \n",
    "    for _ in range(max_iters):\n",
    "        # 计算每个点到中心点的距离，并分配标签\n",
    "        labels = pairwise_distances_argmin_min(X, centroids)[0]\n",
    "        \n",
    "        # 更新中心点\n",
    "        new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(k)])\n",
    "        \n",
    "        # 如果中心点不再变化，则停止迭代\n",
    "        if np.all(centroids == new_centroids):\n",
    "            break\n",
    "        \n",
    "        centroids = new_centroids\n",
    "    \n",
    "    return labels, centroids\n",
    " \n",
    "# 生成虚拟数据并验证k-Means算法\n",
    "X = np.random.rand(100, 2)  # 生成一个100x2的二维点集\n",
    "labels, centroids = kmeans(X, k=3)\n",
    " \n",
    "# 可视化聚类结果（需要完善）\n",
    "plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')\n",
    "plt.scatter(centroids[:, 0], centroids[:, 1], s=300, c='red', marker='X')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4cd546c-74e1-424e-81d9-8778ed5202f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 二、肘部法确定k值\n",
    "def plot_elbow_curve(X):\n",
    "    sse = []\n",
    "    k_range = range(1, 11)  # 尝试的k值范围\n",
    "    for k in k_range:\n",
    "        _, _ = kmeans(X, k)\n",
    "        # 这里需要计算SSE（需要完善，因为上面的kmeans函数没有返回SSE）\n",
    "        # 暂时用labels和centroids的某种计算代替（实际中需要重新实现kmeans以返回SSE）\n",
    "        # sse.append(np.sum(np.min(pairwise_distances(X, centroids[:, np.newaxis]), axis=1)**2))\n",
    "        # 由于上面未返回SSE，这里用sklearn的KMeans来计算（仅作为示例）\n",
    "        kmeans_sklearn = KMeans(n_clusters=k, random_state=42).fit(X)\n",
    "        sse.append(kmeans_sklearn.inertia_)  # inertia_属性即为SSE\n",
    "    \n",
    "    plt.plot(k_range, sse, 'bx-')\n",
    "    plt.xlabel('k')\n",
    "    plt.ylabel('SSE')\n",
    "    plt.title('Elbow Method For Optimal k')\n",
    "    plt.show()\n",
    " \n",
    "# 对虚拟数据应用肘部法\n",
    "plot_elbow_curve(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53d1dba0-078b-4ef2-8ecd-e5aca1a1a22f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 三、图像读取与灰度转换\n",
    "def read_and_convert_image(image_path):\n",
    "    # 使用OpenCV读取图像\n",
    "    image = cv2.imread(image_path)\n",
    "    # 转换为灰度图像\n",
    "    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
    "    return image, gray_image\n",
    " \n",
    "# 读取并转换图像（需要替换为实际图像路径）\n",
    "image_path = 'C:/Users/wuan/Pictures/Camera Roll/123.jpg'\n",
    "image, gray_image = read_and_convert_image(image_path)\n",
    " \n",
    "# 显示原图和灰度图（需要完善可视化部分）\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Original Image')\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.imshow(gray_image, cmap='gray')\n",
    "plt.title('Gray Image')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "46dcb4ac-5b2c-4529-87d0-9670605b3d3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 四、图像背景分割\n",
    "def segment_image(gray_image, k=2):\n",
    "    # 将灰度图像转换为二维数组（高x宽）并重塑为（高*宽，1）以适配k-Means输入\n",
    "    X = gray_image.reshape(-1, 1)\n",
    "    # 应用k-Means算法进行聚类\n",
    "    labels, _ = kmeans(X, k)\n",
    "    # 重塑标签数组以匹配原图像尺寸\n",
    "    segmented_mask = labels.reshape(gray_image.shape)\n",
    "    return segmented_mask\n",
    " \n",
    "# 对灰度图像进行背景分割\n",
    "segmented_mask = segment_image(gray_image, k=2)\n",
    " \n",
    "# 可视化分割结果（需要完善）\n",
    "plt.imshow(segmented_mask, cmap='gray')\n",
    "plt.title('Segmented Mask')\n",
    "\n",
    "plt.show()\n",
    "# 可将蒙版与原图像叠加显示（需要完善）\n",
    "# ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f73e942-2403-49b7-bfb1-377962d482a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 五、图像压缩\n",
    "import cv2\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.cluster import KMeans\n",
    " \n",
    "def compress_image(image, k):\n",
    "    # 将图像转换为二维数组（高x宽x3）并重塑为（高*宽，3）以适配k-Means输入\n",
    "    X = image.reshape(-1, 3)\n",
    "    # 应用k-Means算法进行聚类\n",
    "    kmeans_sklearn = KMeans(n_clusters=k, random_state=42).fit(X)\n",
    "    # 使用聚类中心的颜色代替原图像中对应类别的像素颜色\n",
    "    compressed_image = kmeans_sklearn.cluster_centers_[kmeans_sklearn.labels_].reshape(image.shape[:2] + (3,))\n",
    "    # 转换数据类型为uint8，因为OpenCV图像需要这种类型\n",
    "    compressed_image = compressed_image.astype(np.uint8)\n",
    "    # 由于OpenCV图像是BGR格式，而KMeans默认处理的是RGB，但我们在reshape后已经转换回了正确的通道顺序（虽然这里没显式BGR转换，但通道顺序本身已正确）\n",
    "    # 注意：实际上在这里并没有进行RGB到BGR的转换，因为reshape操作没有改变通道的顺序，只是改变了数组的形状。\n",
    "    # 如果之前处理中有将RGB转为BGR的步骤并遗忘了，那么在这里可能需要加回来，但在这个上下文中不需要。\n",
    "    return compressed_image\n",
    " \n",
    "# 读取图像（需要替换为实际图像路径）\n",
    "image_path = 'C:/Users/wuan/Pictures/Camera Roll/123.jpg'  # 确保替换为有效的路径\n",
    "image = cv2.imread(image_path)\n",
    " \n",
    "# 设置要尝试的k值列表\n",
    "k_values = [2, 4, 8, 16, 32]  # 可以根据需要添加或删除k值\n",
    " \n",
    "# 对每个k值进行图像压缩并显示\n",
    "for k in k_values:\n",
    "    compressed_image = compress_image(image, k)\n",
    "    \n",
    "    # 显示压缩后的图像\n",
    "    plt.figure(figsize=(10, 5))  # 设置图像大小以便更好地查看\n",
    "    plt.imshow(cv2.cvtColor(compressed_image, cv2.COLOR_BGR2RGB))  # 这里仍然需要转换颜色空间以正确显示图像\n",
    "    plt.title(f'Compressed Image (k={k})')\n",
    "    plt.axis('off')  # 关闭坐标轴\n",
    "    plt.savefig('2.png', dpi=300)\n",
    "    plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
